<template>
	<transition @after-leave="handleAfterLeave">
		<div class="mp-micro" v-show="visible" @click.stop="">
			<div class="qo-preview">
				<div class="qo-preview__header">
					<span class="qo-preview--left">文件预览</span>
					<span class="qo-preview--right" @click="close">关闭</span>
				</div>
				<div class="qo-preview__main">
					<transition name="el-message-fade">
						<div class="qo-main--left" v-show="collapse">
							<div class="qo-main--left-img" :class="{'qo-main--left-border':item.url===showImg.url}" v-for="item in list" :key="item.url" @click="switchImg(item)">
								<span class="text ellipsis">
									{{item.name}}
								</span>
							</div>
						</div>
					</transition>
					<div v-loading="pdfLoading" class="qo-main--right">
						<!-- img图片格式预览 -->
						<img v-if="showImg.type === 'img'" :style="imgStyle" @mousewheel='mouseWheelHandler' ref='img' :src="showImg.url" @load="handleImgLoad" @error="handleImgError" @mousedown="handleMouseDown" alt="">
						<!-- pdf格式预览 使用vue-pdf -->
						<pafCom v-else-if="showImg.type === 'pdf'" :style="imgStyle" :rotate="rotate" :currentPage="currentPage" :url="showImg.url" style="width:100%;height:100%;overflow: auto;background: #00000008;" @scroll-page="page => currentPage = scrollPage = page" @all-pages="pages => this.allPage = pages" @load-success="load => pdfLoading = load"></pafCom>
						<!-- office格式 使用微软在线预览 -->
						<iframe v-else-if="officePreviewList.includes(showImg.type)" style="width: 100%;min-height: 600px;" :src="`https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(showImg.url)}`" width='100%' height='100%' frameborder='1' />
						<!-- 音频、视频 -->
						<media-preview v-else-if="mediaPreviewList.includes(showImg.type)" :viewFileUrl="showImg.url" :viewType="showImg.type" :style="imgStyle" :key="showImg.url"></media-preview>
						<!-- 音频、视频 -->
						<code-preview v-else-if="codePreviewList.includes(showImg.type)" :viewFileUrl="showImg.url" :style="imgStyle" :key="showImg.url"></code-preview>
						<!-- 其余展示图片 -->
						<extra-preview v-else :style="imgStyle" :previewType="showImg.suffix"></extra-preview>
						<div class="qo-main--right-tool__left" @click="prev">
							<i class="iconfont el-icon-back"></i>
						</div>
						<div class="qo-main--right-tool__right" @click="next">
							<i class="iconfont el-icon-right"></i>
						</div>
						<div class="qo-main--right-tool">
							<div class="qo-main--side">
								<i :class="collapse ? 'el-icon-s-fold' : 'el-icon-s-unfold'" class="iconfont" @click="collapse = !collapse"></i>
							</div>
							<div v-show="showImg.type === 'pdf'" class="qo-main--page">
								<span @click="handleActions('pageDown')">
									<i class="iconfont iconfangxiang-qian-xian"></i>
								</span> <span>{{scrollPage || currentPage}}/{{allPage}}</span><span @click="handleActions('pageUp')">
									<i class="iconfangxiang-hou-xian iconfont"></i>
								</span>
							</div>
							<div class="qo-main--zoom">
								<span @click="handleActions('zoomOut')">
									<i class="iconfont el-icon-zoom-out"></i>
								</span> <span>{{getScale}}%</span><span @click="handleActions('zoomIn')">
									<i class="el-icon-zoom-in iconfont"></i>
								</span>
							</div>
							<div class="qo-main--rotate" @click="handleActions('clocelise')">
								<i class="V7_iconV7tubiao_zhuanma V7_iconfont"></i>
							</div>
							<div class="qo-main--download">
								<a class="iconfont el-icon-download pointer" style="color:#fff" :href="showImg.url + '?attname=' + showImg.fileName" download target="_blank"></a>
							</div>
							<div class="qo-main--delete" v-if="!isHiddenDelBtn" @click="handleDelete">
								<i class="el-icon-delete iconfont"></i>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</transition>
</template>
<script lang="ts">
import { Component, Vue, Watch, Prop } from 'vue-property-decorator';
import pafCom from './pdf.vue';
import ExtraPreview from './ExtraPreview.vue';
import MediaPreview from './MediaPreview.vue';
import CodePreview from './CodePreview.vue';
@Component({
  name: 'imagePreview',
  components: {
    pafCom,
    ExtraPreview,
    MediaPreview,
    CodePreview
  }
})
export default class extends Vue {
  @Prop({ default: () => [] }) public list!: any;
  @Prop({ default: () => [] }) public img!: any;
  @Prop({ default: false }) public isHiddenDelBtn!: boolean;
  public visible = true;
  private collapse = true; // 控制左侧显示或隐藏
  private currentPage = 1; // pdf当前页
  private rotate = 0; // pdf旋转交付
  private scrollPage = 0;
  private allPage = 1; // pdf总页数
  private pdfLoading = false;
  private showImg: any = {};
  private officePreviewList = ['doc', 'docs', 'ppt', 'pptx', 'xls', 'xlsx']; // 可以通过office在线预览的后缀列表
  private mediaPreviewList = ['video', 'audio'];
  private codePreviewList = ['json', 'txt', 'md']; // 可以使用编辑器在线预览的类型
  private dragHandler: any = '';
  private transform = {
    scale: 1,
    deg: 0,
    offsetX: 0,
    offsetY: 0,
    enableTransition: false
  };

  private loading = false;
  private mouseWheelHandler = this.rafThrottle((e) => {
    const delta = e.wheelDelta ? e.wheelDelta : -e.detail;
    if (delta > 0) {
      this.handleActions('zoomIn', {
        zoomRate: 0.015,
        enableTransition: false
      });
    } else {
      this.handleActions('zoomOut', {
        zoomRate: 0.015,
        enableTransition: false
      });
    }
  });

  @Watch('showImg.url')
  private urlLoading (val) {
    this.$nextTick(() => {
      const $img: any = this.$refs.img;
      if ($img && !$img.complete) {
        this.loading = true;
      }
    });
  }

  private get imgStyle () {
    const { scale, deg, offsetX, offsetY, enableTransition } = this.transform;
    const style = {
      transform: `scale(${scale}) rotate(${deg}deg)`,
      transition: enableTransition ? 'transform .3s' : '',
      marginLeft: `${offsetX}px`,
      marginTop: `${offsetY}px`
    };
    return style;
  }

  private get getScale () {
    return Math.floor(this.transform.scale * 100);
  }

  private close () {
    this.visible = false;
  }

  private created () {
    this.showImg = this.img;
  }

  private switchImg (item) {
    this.resetStyle();
    this.showImg = item;
  }

  private resetStyle () {
    this.pdfLoading = false;
    this.transform = {
      scale: 1,
      deg: 0,
      offsetX: 0,
      offsetY: 0,
      enableTransition: false
    };
    this.scrollPage = 0;
    this.currentPage = 1;
    this.rotate = 0;
  }

  private rafThrottle (fn) {
    let locked = false;
    return function (this: any, ...args) {
      if (locked) {
        return false;
      }
      locked = true;
      window.requestAnimationFrame((_) => {
        fn.apply((this), args);
        locked = false;
      });
    };
  }

  private handleActions (action, options = {}) {
    const { zoomRate, rotateDeg, enableTransition } = {
      zoomRate: 0.2,
      rotateDeg: 90,
      enableTransition: true,
      ...options
    };
    const { transform } = this;
    switch (action) {
      case 'zoomOut':
        if (transform.scale > 0.2) {
          transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3));
        }
        break;
      case 'zoomIn':
        transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3));
        break;
      case 'clocelise':
        if (this.showImg.type === 'pdf') {
          this.rotate += rotateDeg;
        } else {
          transform.deg += rotateDeg;
        }
        break;
      case 'anticlocelise':
        transform.deg -= rotateDeg;
        break;
      case 'pageDown':
        this.scrollPage = 0;
        if (this.currentPage > 1) {
          this.currentPage--;
        }
        break;
      case 'pageUp':
        this.scrollPage = 0;
        if (this.currentPage < this.allPage) {
          this.currentPage++;
        }
        break;
    }
    transform.enableTransition = enableTransition;
  }

  private handleImgLoad (e) {
    this.loading = false;
  }

  private handleImgError (e) {
    this.loading = false;
    e.target.alt = '加载失败';
  }

  private handleMouseDown (e) {
    if (this.loading || e.button !== 0) {
      return;
    }
    const { offsetX, offsetY } = this.transform;
    const startX = e.pageX;
    const startY = e.pageY;
    this.dragHandler = this.rafThrottle((ev) => {
      this.transform.offsetX = offsetX + ev.pageX - startX;
      this.transform.offsetY = offsetY + ev.pageY - startY;
    });
    document.addEventListener('mousemove', this.dragHandler, false);
    document.addEventListener(
      'mouseup',
      (ev) => {
        document.removeEventListener('mousemove', this.dragHandler, false);
      },
      false
    );
    e.preventDefault();
  }

  private prev () {
    this.findImg((index, len) => {
      return index === 0 ? len - 1 : index - 1;
    });
  }

  private next () {
    this.findImg((index, len) => {
      return index === len - 1 ? 0 : index + 1;
    });
  }

  private findImg (fn) {
    const len = this.list.length;
    this.list.find((item, index) => {
      if (item.url === this.showImg.url) {
        this.showImg = this.list[fn(index, len)];
        this.resetStyle();
        return true;
      }
    });
  }

  private handleDelete () {
    const that: any = this;
    that.callback('delete', this.showImg);
    const index = this.list.findIndex((item) => {
      return this.showImg.url === item.url;
    });
    this.list.splice(index, 1);
    if (this.list.length > 0) {
      this.showImg = this.list[index];
    } else {
      this.showImg = {};
    }
  }

  private handleAfterLeave () {
    this.$destroy();
    (this.$el as any).parentNode.removeChild(this.$el);
  }
}
</script>
<style lang="stylus" scoped>
.qo-preview {
	position fixed
	width 100%
	height 100%
	background #FFFFFF
	top 0
	left 0
	z-index 30000
	&__header {
		background #FFFFFF
		box-shadow 0px 4px 8px rgba(0, 0, 0, 0.05)
		padding 10px 24px
		display flex
		.qo-preview--left {
			font-size 20px
			line-height 36px
			color #000000
			opacity 0.8
			flex 1
		}
		.qo-preview--right {
			flex-basis 80px
			text-align center
			border 1px solid rgba(0, 0, 0, 0.1)
			border-radius 4px
			font-size 14px
			line-height 20px
			padding 8px 0
			cursor pointer
			color rgba(0, 0, 0, 0.8)
			&:hover {
				border-color #3a8ee6
			}
		}
	}
	&__main {
		display flex
		height calc(100% - 58px)
		.qo-main--left {
			width 256px
			background rgba(0, 0, 0, 0.03)
			height 100%
			overflow-y auto
			padding 16px
			&-img {
				background #FFFFFF
				border-radius 4px
				padding 8px 10px
				margin-bottom 16px
				font-weight 500
				font-size 14px
				line-height 20px
				color #000000
				opacity 0.8
				cursor pointer
				display flex
				.icon {
					flex-basis 35px
				}
				.text {
					flex 1
					line-height 25px
				}
			}
			&-border {
				border 1px solid #1E63F5
			}
		}
		.qo-main--right {
			flex 1
			position relative
			text-align center
			position relative
			display flex /* Flex布局 */
			display -webkit-flex /* Safari */
			justify-content center
			align-items center /* 指定垂直居中 */
			img {
				max-width 100%
				max-height 100%
			}
			&-tool {
				position absolute
				bottom 40px
				left 50%
				margin-left -161px
				padding 8px 18px
				background rgba(0, 0, 0, 0.8)
				box-shadow 0px 0px 8px rgba(0, 0, 0, 0.05)
				border-radius 32px
				color #fff
				display flex
				.qo-main--side {
					border-right 1px solid rgba(255, 255, 255, 0.3)
					padding-right 18px
				}
				.qo-main--page {
					padding 0 0 0 25px
					.iconfangxiang-qian-xian {
						padding-right 9px
					}
					.iconfangxiang-hou-xian {
						padding-left 9px
					}
				}
				.qo-main--zoom {
					padding 0 35px 0 25px
					.el-icon-zoom-out {
						padding-right 9px
					}
					.el-icon-zoom-in {
						padding-left 9px
					}
				}
				.qo-main--rotate {
					border-right 1px solid rgba(255, 255, 255, 0.3)
					padding-right 26px
				}
				.qo-main--download {
					padding 0 34px 0 24px
				}
				.qo-main--delete {
				}
			}
			&-tool__left {
				position absolute
				cursor pointer
				left 32px
				top 50%
				width 48px
				height 48px
				text-align center
				line-height 48px
				margin-top -24px
				background #FFFFFF
				box-shadow 0px 0px 8px rgba(0, 0, 0, 0.1)
				border-radius 88px
				.iconfont {
					color #000000
					opacity 0.6
				}
			}
			&-tool__left:hover {
				.iconfont {
					color #000000
					opacity 0.8
				}
			}
			&-tool__right {
				position absolute
				cursor pointer
				right 32px
				width 48px
				height 48px
				top 50%
				text-align center
				line-height 48px
				margin-top -24px
				background #FFFFFF
				box-shadow 0px 0px 8px rgba(0, 0, 0, 0.1)
				border-radius 88px
				.iconfont {
					color #000000
					opacity 0.6
				}
			}
			&-tool__right:hover {
				.iconfont {
					color #000000
					opacity 0.8
				}
			}
		}
	}
}
.fade-enter-active, .fade-leave-active {
	transition all 6s ease
}
.fade-enter, .fade-leave-to { /* .fade-leave-active below version 2.1.8 */
	opacity 0
}
.iconfont {
	cursor pointer
}
</style>
